package modele;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.List;

import javax.swing.JFileChooser;

import application.Consts;





public class CKModel<T,S> {
	//MAX number of C or K in our model
	private final static int _MAX_SIZE = 30;
	
	//C Space
	private Concept<T> _cSpace;
	
	//K Space (a Vector)
	private KSpace<Knowledge<S>> _kSpace;
	
	// An array of arrays of the links between C and K
	private boolean[][] _ckLinks;
	
	// Current number of C and K in our model
	private int _currentCsize;
	private int _currentKsize;
	
	//Constructor
	public CKModel(){
		setCSpace(new Concept<T>());
		setKSpace(new KSpace<Knowledge<S>>());
		setCKLinks(new boolean[_MAX_SIZE][_MAX_SIZE]);
		setCSize(1);
	}
	
	/*
	 * Getters and Setters
	 */
	
	/**
	 * @param _cSpace the _cSpace to set
	 */
	public void setCSpace(Concept<T> _cSpace) {
		this._cSpace = _cSpace;
	}

	/**
	 * @return the _cSpace
	 */
	public Concept<T> getCSpace() {
		return _cSpace;
	}

	/**
	 * @param _kSpace the _kSpace to set
	 */
	public void setKSpace(KSpace<Knowledge<S>> _kSpace) {
		this._kSpace = _kSpace;
	}

	/**
	 * @return the _kSpace
	 */
	public KSpace<Knowledge<S>> getKSpace() {
		return _kSpace;
	}

	/**
	 * @param _ckLinks the _ckLinks to set
	 */
	public void setCKLinks(boolean[][] _ckLinks) {
		this._ckLinks = _ckLinks;
		for (int i =0; i<_MAX_SIZE; i++){
			for (int j=0; j<_MAX_SIZE; j++){
				this._ckLinks[i][j] = false;
			}
		}
	}

	/**
	 * @return the _ckLinks
	 */
	public boolean[][] getCKLinks() {
		return _ckLinks;
	}
	
	/**
	 * @param _currentCsize the _currentCsize to set
	 */
	public void setCSize(int _cSize) {
		this._currentCsize = _cSize;
	}

	/**
	 * @return the _currentCsize
	 */
	public int getCSize() {
		return _currentCsize;
	}

	/**
	 * @param _currentKsize the _currentKsize to set
	 */
	public void setKSize(int _kSize) {
		this._currentKsize = _kSize;
	}

	/**
	 * @return the _currentKsize
	 */
	public int getKSize() {
		return _currentKsize;
	}

	/*
	 * Les op�rateurs
	 */
	// K->K
	public void addKnowledge(Knowledge<S> knowledge){
		_kSpace.add(knowledge);
		_currentKsize++;
	}
	
	public void removeKnowledge(Knowledge<S> knowledge){
		_kSpace.remove(knowledge);
		removeLinks(knowledge);
		_currentKsize--;
	}
	
	
	public void removeConcept(int i){
		_cSpace.removeChildAt(i);
		_currentCsize--;
		removeLinks(i);
	}
	
	//C->C
	public void partition(Concept<T> child, Concept<T> parent){
		if(_cSpace.researchIdConcept(parent.getIndex()).getIndex() != -1){
		parent.addChild(child);
		_currentCsize++;
		}
	}
	
	public void departition(Concept<T> nouveauC0){
		nouveauC0.addChild(this._cSpace);
		this.setCSpace(nouveauC0);
		_currentCsize++;
	}
	
	//C->K et K->C
	public void addLink(Concept<T> concept, Knowledge<S> knowledge){
	//	if(_cSpace.researchIdConcept(concept.getIndex()).getIndex() != -1){
			_ckLinks[knowledge.getIndex()][concept.getIndex()] =  true;
	//	}
	}
	
	public void removeLink(Concept<T> concept, Knowledge<S> knowledge){
		_ckLinks[knowledge.getIndex()][concept.getIndex()] =  false;
	}
	
	public void removeLinks(int indice){
		for(int i=0; i<_kSpace.size(); i++){
			_ckLinks[i][indice] = false;
		}
	}
	
	public void removeLinks(Knowledge<S> knowledge){
		for(int i=0; i<_MAX_SIZE; i++){
			_ckLinks[knowledge.getIndex()][i] = false;
		}
	}
	
	/**
	 * Methods for visualisation
	 */
	
	public String toString(){
		return "C-Space : " + _cSpace.toStringArborescence() +"\nK-Space : " + _kSpace.toString();
	}
	
	/**
	 * Return C Space in String
	 * @return
	 */
	public String cSpaceToString(){
		String result = new String();
		for (int i=0; i<_currentCsize; i++){
			result += _cSpace.researchIdConcept(i).toString();
			result += Consts.NEW_LINE;
		}
		return result;
	}
	
	/**
	 * Return K Space in String
	 * @return
	 */
	public String kSpaceToString(){
		String result = new String();
		for(int i=0; i<_kSpace.size(); i++){
			result += _kSpace.elementAt(i).toString();
			result += Consts.NEW_LINE;
		}
		
		return result;
	}
	
	/**
	 * Return array of links between C and K space in String 
	 * @return
	 */
	public String ckLinksArrayToString(){
		String result = new String();
		// 1st line :
		result += "  ";
		// Print the different K
		for (int i=0; i < getKSize(); i++){
			result += "  K" +i; 
		}
		result += Consts.NEW_LINE;
		
		//For each new concept
		for (int j=0; j<getCSize(); j++){
			result+= "C" + j;
			//Print line
			for (int i=0; i < getKSize(); i++){
				result += " "; 
				if (_ckLinks[_kSpace.elementAt(i).getIndex()][j]){
					result += "x";
				} else {
					result += " ";
				}
				result += "  ";
			}
			result+= Consts.NEW_LINE;
		}
		
		return result;
	}
	
	// TODO: a quoi sert cette fonction?
	public String researchDataConcept(T data){
		return _cSpace.researchDataConcept(data).toString();
	}
	
	/**
	 * Moves Subtree starting to new place in tree
	 * @param oldParent
	 * @param child
	 * @param newParent
	 */
	public void moveSubTree(Concept<T> oldParent, Concept<T> child, Concept<T> newParent){
		newParent.addChild(child);
		oldParent.removeChild(child);
	}
	
	 public List<Concept<T>> researchData(T data){
		 return _cSpace.researchDataConcept(data);
	 }
	
	 public Concept<T> findConceptFromId(int i){
		 return _cSpace.researchIdConcept(i);
	 }
	 
	 
	 /**
	  * Save the CK to a file (saving class as an XML)
	  */
	public void save() {
		 
		JFileChooser fc = new JFileChooser();
		int returnVal = fc.showSaveDialog(fc);
		
		File file = new File("defaut.xml");
		
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			 XMLEncoder enc;
			 file = fc.getSelectedFile();
			 if(!file.getName().toLowerCase().endsWith(".xml")){
	            	String filePath = file.getPath().concat(".xml");
	            	file = new File(filePath);
	            } else {
	            	file = new File(file.getPath());
	            }
			try {
				FileOutputStream fops = new FileOutputStream(file);
				enc = new XMLEncoder(fops);
				enc.writeObject(this);
				enc.close();
				
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
		
	/**
	 * Loads a CK model from a XML java class file
	 * @param modele
	 */
	@SuppressWarnings("unchecked")
	public CKModel<String, String> load(){
		 
		CKModel<String, String> modele = new CKModel<String, String>();
		
		JFileChooser fc = new JFileChooser();
		int returnVal = fc.showOpenDialog(fc);
		
		File file = new File("defaut.xml");
		
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			XMLDecoder dec;
            file = fc.getSelectedFile();
            file = new File(file.getPath());
			
            if(file.getName().toLowerCase().endsWith(".xml")){
				try {
					FileInputStream fips = new FileInputStream(file);
					dec = new XMLDecoder(fips);
				
						 modele = (CKModel<String, String>) dec.readObject();
						 dec.close();
						 
				} catch (FileNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
            }
		}
		return modele;
	 }
	 
}
